#include "config.h"
#include "stream.h"
#include "./map.h"
#include "./list.h"
#include "./string.h"
KL_BEGIN	
template<typename Type = KL::string,
	typename Allocate = KL::allocator<Type> >
class Xml
{	// Template Arg <Type> should at least has functions
	//	string(); 
	//	string(char const *); 
	//	string(const string &);
	//	const char *data() const; 
	//	size_t size() const;
public:
	struct node_type;
	typedef Type key_type;
	typedef Type value_type;
	typedef KL::map<key_type, value_type, KL::less<key_type>, Allocate> proper_map;
	typedef KL::list<Xml<Type, Allocate> > sub_list;
protected:
	Xml * _parent;
	sub_list * _subs;
public:
	proper_map propers;
	key_type name;
	value_type text;
public:
	Xml()
		: name("xml")
		, _parent(0)
		, _subs(new sub_list() )
	{
	}
	Xml(Xml const &o)
		: name(o.name)
		, text(o.text)
		, propers(o.propers)
		, _parent(o._parent)
		, _subs(new sub_list())
	{	// warning: dont copy subs.
		// you may use "set(...)" like "xml.set(o.get());" to copy that.
	}
	Xml(key_type const &name, Xml * parent)
		: name(name)
		, _parent(parent)
		, _subs(new sub_list() )
	{
	}
	bool is_root() const
	{
		return _parent == 0;
	}
	Xml & parent()
	{
		ASSERT(_parent);
		return *_parent;
	}
	Xml & add(key_type const & name)
	{
		_subs->push_back(Xml(name, this));
		return _subs->back();
	}
	void set(sub_list const & subs)
	{
		*(_subs) = subs;
	}
	sub_list & get()
	{
		return *_subs;
	}
	~Xml()
	{
		delete(_subs);
	}
	// Transform to string.
	// Template Arg <String> should at least has functions:
	//	.. append(char const *);
	//	.. push_back(char);
	template<typename String>
	void str(String &dest) const
	{
		this->str_head(dest);
		this->str_text(dest);
		this->str_subs(dest);
		this->str_tail(dest);
	}
	template<typename String>
	void str_node(String &dest) const
	{
		this->str_head(dest);
		this->str_text(dest);
		this->str_tail(dest);
	}
	template<typename String>
	void str_subs(String &dest) const
	{
		for(sub_list::const_iterator iter = _subs->begin();
			iter != _subs->end(); ++iter)
			iter->str(dest);
	}
	template<typename String>
	void str_subs_node(String &dest) const
	{
		for(sub_list::const_iterator iter = _subs->begin();
			iter != _subs->end(); ++iter)
			iter->str_node(dest);
	}
	template<typename String>
	void str_head(String &dest) const
	{
		dest.push_back('<');
		dest.append(name.data(), name.size());
		if(!propers.empty()) str_proper(dest);
		dest.push_back('>');
	}
	template<typename String>
	void str_text(String &dest) const
	{
		dest.append(text.data(), text.size());
	}
	template<typename String>
	void str_tail(String &dest) const
	{
		dest.push_back('<');
		dest.push_back('/');
		dest.append(name.data(), name.size());			
		dest.push_back('>');
	}
	template<typename String>
	void str_proper(String &dest) const
	{
		for(proper_map::const_iterator iter = propers.begin();
			iter != propers.end(); ++iter)
		{	
			dest.push_back('\x20');
			dest.append(iter->first.data(), iter->first.size());
			dest.append("='");
			dest.append(iter->second.data(), iter->second.size());
			dest.push_back('\'');
		}
	}
};
KL_END
